#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned int DWORD;
#define IMAGE_SIZEOF_SHORT_NAME 8 // 宏定义
#define DOS_MAGIC 0x5A4D

#define FILE_HEAD_MACHINE_64 0x8664
#define FILE_HEAD_MACHINE_32 0x014C
#define MESSAGEBOXAADDR 0x76000720
#define SELLCODESIZE 18

BYTE shellCode[] = {
	0x6A, 00, 0x6A, 00, 0x6A, 00, 0x6A, 00,
	0xE8, 00, 00, 00, 00,
	0xE9, 00, 00, 00, 00};

typedef struct PEDos
{
	WORD e_magic;	 // DOS签名 "MZ" (0x5A4D)
	WORD e_cblp;	 // 文件最后一页的字节数
	WORD e_cp;		 // 文件中的页数
	WORD e_crlc;	 // 重定位条目数
	WORD e_cparhdr;	 // 头部段数
	WORD e_minalloc; // 最小额外内存需求
	WORD e_maxalloc; // 最大额外内存需求
	WORD e_ss;		 // 初始SS值（堆栈段）
	WORD e_sp;		 // 初始SP值（堆栈指针）
	WORD e_csum;	 // 校验和
	WORD e_ip;		 // 初始IP值（指令指针）
	WORD e_cs;		 // 初始CS值（代码段）
	WORD e_lfarlc;	 // 重定位表偏移
	WORD e_ovno;	 // 覆盖号
	WORD e_res[4];	 // 保留字段
	WORD e_oemid;	 // OEM标识符
	WORD e_oeminfo;	 // OEM信息
	WORD e_res2[10]; // 保留字段
	DWORD e_lfanew;	 // PE头偏移（关键字段！）
} PEDos;

typedef struct _IMAGE_FILE_HEADER
{
	WORD Machine;				// 目标CPU架构（如0x014C=x86, 0x8664=x64）
	WORD NumberOfSections;		// 节表（Section Table）的数量
	DWORD TimeDateStamp;		// 文件创建时间戳
	DWORD PointerToSymbolTable; // 符号表偏移（已废弃）
	DWORD NumberOfSymbols;		// 符号数量（已废弃）
	WORD SizeOfOptionalHeader;	// 可选头的大小（32位=0xE0, 64位=0xF0）
	WORD Characteristics;		// 文件属性（如可执行/DLL/系统文件）
} IMAGE_FILE_HEADER;

// 导出表地址信息
typedef struct _IMAGE_DATA_DIRECTORY
{
	DWORD VirtualAddress;
	DWORD Size;
} IMAGE_DATA_DIRECTORY;

// 导出表结构
typedef struct _IMAGE_EXPORT_DIRECTORY
{
	DWORD Characteristics;		 // 未使用
	DWORD TimeDateStamp;		 // 时间戳
	WORD MajorVersion;			 // 未使用
	WORD MinorVersion;			 // 未使用
	DWORD Name;					 // 指向该导出表文件名字符串
	DWORD Base;					 // 导出函数起始序号
	DWORD NumberOfFunctions;	 // 所有导出函数的个数
	DWORD NumberOfNames;		 // 以函数名字导出的函数个数
	DWORD AddressOfFunctions;	 // 导出函数地址表RVA
	DWORD AddressOfNames;		 // 导出函数名称表RVA
	DWORD AddressOfNameOrdinals; // 导出函数序号表RVA
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

// 重定位表结构
typedef struct _IMAGE_BASE_RELOCATION
{
	DWORD VirtualAddress;
	DWORD SizeOfBlock;
	// 一堆数据...（如果是最后一个这种结构，就只有RVA和SizeOfBlock，且都为0）
} IMAGE_BASE_RELOCATION, *PIMAGE_BASE_RELOCATION;

// INT表
typedef struct _IMAGE_IMPORT_BY_NAME
{
	WORD Hint;	  // 可能为空（编译器决定）；如果不为空，表示函数在导出表中的索引
	BYTE Name[1]; // 函数名称，以0结尾
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

// IAT表
typedef struct _IMAGE_THUNK_DATA32
{
	union
	{
		BYTE ForwarderString;
		DWORD Function;
		DWORD Ordinal;						  // 序号
		_IMAGE_IMPORT_BY_NAME *AddressOfData; // RVA，指向IMAGE_IMPORT_BY_NAME
	};
} IMAGE_THUNK_DATA32, *PIMAGE_THUNK_DATA32;

// 导入表
typedef struct _IMAGE_IMPORT_DESCRIPTOR
{
	union
	{
		DWORD Characteristics;	  // 导入表结束标志
		DWORD OriginalFirstThunk; // RVA指向一个结构体数组(INT表)
	};
	DWORD TimeDateStamp;  // 时间戳
	DWORD ForwarderChain; // -1 if no forwarders
	DWORD Name;			  // RVA指向dll名字，以0结尾
	DWORD FirstThunk;	  // RVA指向一个结构体数组(IAT表)
} IMAGE_IMPORT_DESCRIPTOR, *PIMAGE_IMPORT_DESCRIPTOR;

typedef struct _IMAGE_OPTIONAL_HEADER
{
	WORD Magic; // 标识类型（0x10B=32位, 0x20B=64位）
	BYTE MajorLinkerVersion;
	BYTE MinorLinkerVersion;
	DWORD SizeOfCode;
	DWORD SizeOfInitializedData;
	DWORD SizeOfUninitializedData;
	DWORD AddressOfEntryPoint; // 程序入口点（RVA）
	DWORD BaseOfCode;
	DWORD BaseOfData;
	DWORD ImageBase;		// 默认加载基址（如0x00400000）
	DWORD SectionAlignment; // 内存对齐（如0x1000）
	DWORD FileAlignment;	// 文件对齐（如0x200）
	WORD MajorOperatingSystemVersion;
	WORD MinorOperatingSystemVersion;
	WORD MajorImageVersion;
	WORD MinorImageVersion;
	WORD MajorSubsystemVersion;
	WORD MinorSubsystemVersion;
	DWORD Win32VersionValue;
	DWORD SizeOfImage;
	DWORD SizeOfHeaders;
	DWORD CheckSum;
	WORD Subsystem;
	WORD DllCharacteristics;
	DWORD SizeOfStackReserve;
	DWORD SizeOfHeapReserve;
	DWORD SizeOfHeapCommit;
	DWORD LoaderFlags;
	DWORD NumberOfRvaAndSizes; // 数据目录表
} IMAGE_OPTIONAL_HEADER64;

typedef struct _IMAGE_OPTIONAL_HEADER32_1
{
	WORD Magic;						  // 标识类型（0x10B=32位, 0x20B=64位）
	BYTE MajorLinkerVersion;		  // 1字节 链接器版本号
	BYTE MinorLinkerVersion;		  // 1字节 链接器版本号 链接器 是一个将编译器产生的目标文件打包成可执行文件或者库文件或者目标文件的程序。
	DWORD SizeOfCode;				  // 所有代码节的总和 文件对齐后的大小 由编译器填写
	DWORD SizeOfInitializedData;	  // 包含所有已经初始化数据的节的总和 文件对齐后的大小 由编译器填写
	DWORD SizeOfUninitializedData;	  // 包含所有未初始化数据的节的大小 文件对齐后的大小 由编译器填写
	DWORD AddressOfEntryPoint;		  // 程序入口点（RVA）
	DWORD BaseOfCode;				  // 代码开始的基址 由编译器填写
	DWORD BaseOfData;				  // 数据开始的基址 由编译器填写
	DWORD ImageBase;				  // 默认加载基址（如0x00400000）
	DWORD SectionAlignment;			  // 内存对齐（如0x1000）
	DWORD FileAlignment;			  // 文件对齐（如0x200）
	WORD MajorOperatingSystemVersion; // 标识操作系统的版本号 主版本号
	WORD MinorOperatingSystemVersion; //  标识操作系统的版本号 次版本号
	WORD MajorImageVersion;			  // PE文件自身版本号
	WORD MinorImageVersion;			  // PE文件自身版本号
	WORD MajorSubsystemVersion;		  // 运行所需子系统的版本号
	WORD MinorSubsystemVersion;		  // 运行所需子系统的版本号
	DWORD Win32VersionValue;		  // 子系统版本的值，必须为0
	DWORD SizeOfImage;				  // 内存中整个PE文件的映射文件的尺寸，可以大，且必须是SectionAignment的整数倍
	DWORD SizeOfHeaders;			  // 所有头+节表按照文件对齐后的大小，否则加载会出错，且必须是FileAlignment的整数倍
	DWORD CheckSum;					  // 检验和，一些系统文件有要求，用来判断文件是否被修改,通过把PE文件以WORD为单位对数据块进行累加,将累加和加上文件的长度,最后比对该成员的值，如果不一样就是被修改过
	WORD Subsystem;
	WORD DllCharacteristics;
	DWORD SizeOfStackReserve;
	DWORD SizeOfStackCommit;
	DWORD SizeOfHeapReserve;
	DWORD SizeOfHeapCommit;
	DWORD LoaderFlags;
	DWORD NumberOfRvaAndSizes; // 数据目录表
	_IMAGE_DATA_DIRECTORY DataDirectory[16];
} IMAGE_OPTIONAL_HEADER32_1;

typedef struct _IMAGE_OPTIONAL_HEADER32
{
	//
	// Standard fields.
	//

	WORD Magic;
	BYTE MajorLinkerVersion;
	BYTE MinorLinkerVersion;
	DWORD SizeOfCode;
	DWORD SizeOfInitializedData;
	DWORD SizeOfUninitializedData;
	DWORD AddressOfEntryPoint;
	DWORD BaseOfCode;
	DWORD BaseOfData;

	//
	// NT additional fields.
	//

	DWORD ImageBase;
	DWORD SectionAlignment;
	DWORD FileAlignment;
	WORD MajorOperatingSystemVersion;
	WORD MinorOperatingSystemVersion;
	WORD MajorImageVersion;
	WORD MinorImageVersion;
	WORD MajorSubsystemVersion;
	WORD MinorSubsystemVersion;
	DWORD Win32VersionValue;
	DWORD SizeOfImage;
	DWORD SizeOfHeaders;
	DWORD CheckSum;
	WORD Subsystem;
	WORD DllCharacteristics;
	DWORD SizeOfStackReserve;
	DWORD SizeOfStackCommit;
	DWORD SizeOfHeapReserve;
	DWORD SizeOfHeapCommit;
	DWORD LoaderFlags;
	DWORD NumberOfRvaAndSizes;
	IMAGE_DATA_DIRECTORY DataDirectory[16];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

// 64位版本（注意OptionalHeader结构不同）
typedef struct PE_NT_Head
{
	DWORD Signature;
	IMAGE_FILE_HEADER FileHeader;
	IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} PE_NT_Head;

// 节表
typedef struct _IMAGE_SECTION_HEADER
{
	BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; // 每一个节都可以取一个名字，最大长度为8字节
	union
	{
		DWORD PhysicalAddress;
		DWORD VirtualSize;
	} Misc;					// Misc就是此联合体类型的变量，是该节在没有对齐前的真实尺寸,该值可以不准确。
	DWORD VirtualAddress;	// 节区在内存中的偏移地址。加上ImageBase才是在内存中的真正地址.
	DWORD SizeOfRawData;	//  节在文件中对齐后的尺寸.
	DWORD PointerToRawData; // 节区在文件中的偏移.
	DWORD PointerToRelocations;
	DWORD PointerToLinenumbers;
	WORD NumberOfRelocations;
	WORD NumberOfLinenumbers;
	DWORD Characteristics; // 节的属性
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

// 把exe文件读取到内存
void *readExe(char *exePath)
{
	FILE *file = fopen(exePath, "rb");
	if (file == NULL)
	{
		printf("文件打开失败！\n");
		return NULL;
	}

	// 将文件指针移动到末尾
	fseek(file, 0, SEEK_END);
	// 获取文件大小
	long file_size = ftell(file);
	// 将文件指针移动到开头
	fseek(file, 0, SEEK_SET);

	void *apply_space = (void *)malloc(file_size);
	if (apply_space == NULL)
	{
		printf("申请内存失败！\n");
		return NULL;
	}

	// 把空间清0
	memset(apply_space, 0, file_size);

	size_t read_count = fread(apply_space, 1, file_size, file);
	if (read_count != file_size)
	{
		printf("处理读取不完整！\n");
		fclose(file);
		free(apply_space);
		return NULL;
	}

	printf("文件在内存位置：%x\n", apply_space);

	fclose(file);
	return apply_space;
}

PE_NT_Head *getNTHead(void *pePtr)
{
	PEDos *dos_head = (PEDos *)pePtr;
	PE_NT_Head *nt_head = (PE_NT_Head *)(((long)dos_head) + dos_head->e_lfanew);
	return nt_head;
}

// 获取拉伸后的内存大小
DWORD getSizeOfImage(void *pePtr)
{
	return getNTHead(pePtr)->OptionalHeader.SizeOfImage;
}

// 获取节表数量
WORD getNumberOfSections(void *pePtr)
{
	return getNTHead(pePtr)->FileHeader.NumberOfSections;
}

// 获取文件头大小
DWORD getSizeOfHeads(void *pePtr)
{
	return getNTHead(pePtr)->OptionalHeader.SizeOfHeaders;
}

// 获取文件对齐
DWORD getFileAlignment(void *pePtr)
{
	return getNTHead(pePtr)->OptionalHeader.FileAlignment;
}

// 获取内存对齐
DWORD getSectionAlignment(void *pePtr)
{
	return getNTHead(pePtr)->OptionalHeader.SectionAlignment;
}

// 把exe文件写到文件
void writeExe(char *exePath, void *pePtr, DWORD size_of_image)
{
	FILE *file = fopen(exePath, "wb");
	if (file == NULL)
	{
		printf("文件打开失败！\n");
		return;
	}
	PEDos *tmp = (PEDos *)pePtr;
	printf("测试：%x\n", tmp->e_magic);

	size_t elements_written = fwrite(pePtr, 1, size_of_image, file);
	if (elements_written != 0)
	{
		printf("数据写入失败！\n");
		strerror(errno);
		perror("详细错误");
		if (feof(file))
			printf("到达文件末尾\n");
		if (ferror(file))
			perror("写入错误");
		fclose(file);
		return;
	}

	// 3. 关闭文件
	fclose(file);
	printf("数据成功写入文件！\n");
}

void writeTest(char *exePath)
{
	FILE *file = fopen(exePath, "wb+");
	if (file == NULL)
	{
		printf("文件打开失败！\n");
		return;
	}

	char str[] = {'h', 'e'};
	size_t elements_written = fwrite(str, 1, 1, file);

	if (elements_written != 0)
	{
		printf("数据写入失败！\n");
		strerror(errno);
		perror("详细错误");
		if (feof(file))
			printf("到达文件末尾\n");
		if (ferror(file))
			perror("写入错误");
		fclose(file);
		return;
	}

	// 3. 关闭文件
	fclose(file);
	printf("数据成功写入文件！\n");
}

IMAGE_SECTION_HEADER **getSectionHeadStart(void *pePtr)
{

	PEDos *dos_head = (PEDos *)pePtr;
	PE_NT_Head *nt_head = getNTHead(pePtr);

	// 偏移到节表起始位置
	IMAGE_SECTION_HEADER *section_head_ptr = (IMAGE_SECTION_HEADER *)(((long)pePtr) + dos_head->e_lfanew + sizeof(nt_head->Signature) + sizeof(IMAGE_FILE_HEADER) + nt_head->FileHeader.SizeOfOptionalHeader);
	// printf("PE起始地址：%x\n", pePtr);
	// printf("节表首地址:%x\n", section_head_ptr);

	// 获取节表数量
	WORD number_of_sections = getNumberOfSections(pePtr);
	// printf("节表数量:%d\n", number_of_sections);
	//  定义指针数组
	IMAGE_SECTION_HEADER **section_heads = (IMAGE_SECTION_HEADER **)malloc(number_of_sections * sizeof(IMAGE_SECTION_HEADER));

	for (int section_num = 0; section_num <= number_of_sections; section_num++)
	{
		char name[9] = {0};
		int i = 0;
		for (; i < 8; i++)
		{
			name[i] = section_head_ptr->Name[i];
		}
		name[i] = '\0';
		// printf("节表名称：%s\n", name);
		// printf("节表地址：%x\n", section_head_ptr);
		section_heads[section_num] = section_head_ptr;
		section_head_ptr++;
	}

	return section_heads;
}

void *readImageBuffer(void *pePtr)
{
	DWORD size_of_image = getSizeOfImage(pePtr);
	printf("内存拉伸后大小:%d\n", size_of_image);

	// 构建新内存空间（内存对齐的空间）
	void *new_memory = malloc(size_of_image);
	if (new_memory == NULL)
	{
		printf("申请内存失败！\n");
		return NULL;
	}

	// 清空新内存空间（内存对齐的空间）
	memset(new_memory, 0, size_of_image);

	DWORD size_of_heads = getSizeOfHeads(pePtr);
	// 把PE所有的头拷贝过去
	memcpy(new_memory, pePtr, size_of_heads);

	// 获取所有节表
	IMAGE_SECTION_HEADER **section_heads = getSectionHeadStart(pePtr);
	// 获取节表数量
	WORD number_of_sections = getNumberOfSections(pePtr);
	// 拷贝节
	for (int i = 0; i < number_of_sections; i++)
	{
		IMAGE_SECTION_HEADER *section_ptr = section_heads[i];
		DWORD max_value = section_ptr->SizeOfRawData;
		if (section_ptr->SizeOfRawData < section_ptr->Misc.VirtualSize)
		{
			max_value = section_ptr->Misc.VirtualSize;
		}
		void *new_section_addr = (void *)(((long)new_memory) + section_ptr->VirtualAddress);
		void *file_start_addr = (void *)((DWORD)pePtr + section_ptr->PointerToRawData);
		memcpy(new_section_addr, file_start_addr, max_value);
	}

	return new_memory;
}

// 将ImageBuffer变成FileBuffer
void *imageBufferConvertFileBuffer(void *imageBufferPtr)
{
	// 获取imageBase
	PE_NT_Head *pe_nt_head = getNTHead(imageBufferPtr);
	DWORD image_base = pe_nt_head->OptionalHeader.ImageBase;

	// 获取所有节表
	IMAGE_SECTION_HEADER **section_heads = getSectionHeadStart(imageBufferPtr);
	// 获取节表数量
	WORD number_of_sections = getNumberOfSections(imageBufferPtr);
	// 获取最后一个节表
	IMAGE_SECTION_HEADER *last_section_head = section_heads[number_of_sections - 1];
	// 最后一个节表和开头的偏移
	DWORD last_section_offset = last_section_head->PointerToRawData;
	// 根据最后一个节的偏移 + 最后一个节在文件对齐的大小 = fileBuffer大小
	DWORD file_image_buffer_size = last_section_offset + last_section_head->SizeOfRawData;

	// 申请空间
	void *file_image_memory = malloc(file_image_buffer_size);
	if (file_image_memory == NULL)
	{
		printf("申请内存失败！\n");
		return NULL;
	}

	// 重置为0
	memset(file_image_memory, 0, file_image_buffer_size);

	// 获取PE Head头的大小
	DWORD size_of_heads = getSizeOfHeads(imageBufferPtr);
	// 把PE所有的头拷贝过去
	memcpy(file_image_memory, imageBufferPtr, size_of_heads);

	PEDos *tmp = (PEDos *)file_image_memory;
	printf("测试：%x\n", tmp->e_magic);

	// 拷贝节
	for (int i = 0; i < number_of_sections; i++)
	{
		IMAGE_SECTION_HEADER *section_ptr = section_heads[i];
		DWORD max_value = section_ptr->SizeOfRawData;
		if (section_ptr->SizeOfRawData < section_ptr->Misc.VirtualSize)
		{
			max_value = section_ptr->Misc.VirtualSize;
		}
		void *new_section_addr = (void *)(((long)file_image_memory) + section_ptr->PointerToRawData);
		void *file_start_addr = (void *)((DWORD)imageBufferPtr + section_ptr->VirtualAddress);
		memcpy(new_section_addr, file_start_addr, max_value);
	}

	writeExe("H:\\new\\PETool 1.0.0.55.exe", file_image_memory, file_image_buffer_size);
	return file_image_memory;
}

// 将内存偏移转换为文件偏移
void *RvaToFileOffset(void *pePtr, DWORD rvaValue)
{
	// 获取所有节表
	IMAGE_SECTION_HEADER **section_heads = getSectionHeadStart(pePtr);
	// 获取节表数量
	WORD number_of_sections = getNumberOfSections(pePtr);

	// 获取偏移
	DWORD offset_rvaValue = rvaValue;

	// 定义最终找到的节表地址
	IMAGE_SECTION_HEADER *final_section_head = NULL;

	for (int i = 0; i < number_of_sections; i++)
	{
		IMAGE_SECTION_HEADER *current_section_head = section_heads[i];
		// 获取最大边界值
		DWORD boundary_value = current_section_head->VirtualAddress + current_section_head->Misc.VirtualSize;

		// 如果偏移地址大于 当前节表的起始地址，但是小于当前节表最大边界值，说明找到了我们要的节表
		if (offset_rvaValue >= current_section_head->VirtualAddress && offset_rvaValue < boundary_value)
		{
			final_section_head = current_section_head;
			break;
		}
	}

	// 获取最终偏移
	DWORD final_offset_rvaValue = offset_rvaValue - final_section_head->VirtualAddress;
	// 获取在文件中的偏移
	final_offset_rvaValue = final_offset_rvaValue + final_section_head->PointerToRawData;
	return (void *)final_offset_rvaValue;
}

void *FoaToRvaOffset(void *pePtr, DWORD foaValue)
{
	// 获取所有节表
	IMAGE_SECTION_HEADER **section_heads = getSectionHeadStart(pePtr);
	// 获取节表数量
	WORD number_of_sections = getNumberOfSections(pePtr);

	IMAGE_SECTION_HEADER *final_section_head = NULL;
	for (int i = 0; i < number_of_sections; i++)
	{
		IMAGE_SECTION_HEADER *current_section_head = section_heads[i];
		// 获取最大边界值
		DWORD maxValue = current_section_head->SizeOfRawData > current_section_head->Misc.VirtualSize ? current_section_head->SizeOfRawData : current_section_head->Misc.VirtualSize;
		DWORD boundary_value = current_section_head->PointerToRawData + maxValue;
		if (foaValue >= current_section_head->PointerToRawData && foaValue < boundary_value)
		{
			final_section_head = current_section_head;
			break;
		}
	}

	DWORD final_offset_rvaValue = foaValue - final_section_head->PointerToRawData;
	// 获取在内存中的偏移
	final_offset_rvaValue = final_offset_rvaValue + final_section_head->VirtualAddress;
	return (void *)final_offset_rvaValue;
}

void TestAddCodeInCodeSec()
{
	// void* pePtr = readExe("C:\\Windows\\System32\\notepad.exe");
	void *pePtr = readExe("H:\\PETool 1.0.0.5.exe");
	pePtr = readImageBuffer(pePtr);
	// 获取所有节表
	IMAGE_SECTION_HEADER **section_heads = getSectionHeadStart(pePtr);

	// 获取imageBase
	PE_NT_Head *pe_nt_head = getNTHead(pePtr);
	DWORD image_base = pe_nt_head->OptionalHeader.ImageBase;

	// 获取程序入口点
	DWORD AddressOfEntryPoint = pe_nt_head->OptionalHeader.AddressOfEntryPoint;
	DWORD run_address = image_base + AddressOfEntryPoint;

	// 获取第一个节表
	IMAGE_SECTION_HEADER *section_head = section_heads[0];
	// 如果节表大小超过预估大小就跳过
	if ((section_head->SizeOfRawData - section_head->Misc.VirtualSize) < SELLCODESIZE)
	{
		return;
	}

	// 找到空白区
	void *section_non_addr = (void *)(((DWORD)pePtr) + section_head->VirtualAddress + section_head->Misc.VirtualSize);
	// 复制代码
	memcpy(section_non_addr, shellCode, SELLCODESIZE);

	DWORD *e8_addr = (DWORD *)((DWORD)section_non_addr + 0x9);
	*e8_addr = (MESSAGEBOXAADDR - (image_base + section_head->VirtualAddress + section_head->Misc.VirtualSize + 0xD));

	char *e8_addr_tmp = (char *)((DWORD)section_non_addr + 0x8);
	printf("输出：%02hhX\n", *e8_addr_tmp);
	printf("输出：%x\n", *e8_addr);

	DWORD *e9_addr = (DWORD *)((DWORD)section_non_addr + 0xE);
	*e9_addr = run_address - (image_base + section_head->VirtualAddress + section_head->Misc.VirtualSize + SELLCODESIZE);

	char *e9_addr_tmp = (char *)((DWORD)section_non_addr + 0xD);
	printf("输出：%02hhX\n", *e9_addr_tmp);
	printf("输出：%x\n", *e9_addr);

	pe_nt_head->OptionalHeader.AddressOfEntryPoint = (image_base + section_head->VirtualAddress + section_head->Misc.VirtualSize) - image_base;
	pePtr = imageBufferConvertFileBuffer(pePtr);
}

// 在任意节上添加代码
void TestAddCodeAnySection(int num)
{
	// ---------------- FileBuffer ----------------
	// 把exe文件加载到内存
	void *pePtr = readExe("H:\\PETool 1.0.0.5.exe");

	// 获取NT头
	PE_NT_Head *nt_head_ptr = (PE_NT_Head *)((DWORD)pePtr + ((PEDos *)pePtr)->e_lfanew);

	// 获取节表数量
	DWORD numberOfSections = nt_head_ptr->FileHeader.NumberOfSections;
	// 判断要在哪个节加的代码 是不是 超过了节表最大值
	if (num > numberOfSections)
	{
		return;
	}

	// ---------------- FileBuffer ----------------

	// ---------------- ImageBuffer ----------------

	// 将FileBuffer 变成 ImageBuffer
	pePtr = readImageBuffer(pePtr);

	// 获取NT头，获取ImageBase，获取OEP
	nt_head_ptr = getNTHead(pePtr);
	DWORD image_base = nt_head_ptr->OptionalHeader.ImageBase;
	DWORD addressOfEntryPoint = nt_head_ptr->OptionalHeader.AddressOfEntryPoint;

	// 检索这个节的空间是否足够
	IMAGE_SECTION_HEADER *section_heads = (IMAGE_SECTION_HEADER *)((DWORD)pePtr + ((PEDos *)pePtr)->e_lfanew + 4 + 20 + nt_head_ptr->FileHeader.SizeOfOptionalHeader);
	// 获取要注入代码的段
	IMAGE_SECTION_HEADER *current_head = section_heads;
	for (int i = 1; i <= numberOfSections; i++)
	{
		if (i == num)
		{
			break;
		}
		current_head++;
	}
	// 空间不足 表示注入不了
	if (current_head->Misc.VirtualSize - current_head->SizeOfRawData < SELLCODESIZE)
	{
		return;
	}

	// 获取代码节点起始位置
	void *codeBegin = (void *)((DWORD)pePtr + current_head->VirtualAddress + current_head->Misc.VirtualSize);

	// 将代码拷贝过去
	memccpy(codeBegin, shellCode, 1, SELLCODESIZE);

	// 修改E8
	DWORD *e8_code_ptr = (DWORD *)((DWORD)codeBegin + 0x9);
	*e8_code_ptr = (DWORD)(MESSAGEBOXAADDR - (image_base + current_head->VirtualAddress + current_head->Misc.VirtualSize + 0xD));

	// 修改E9
	DWORD *e9_code_ptr = (DWORD *)((DWORD)codeBegin + 0xE);
	*e9_code_ptr = (image_base + addressOfEntryPoint) - (image_base + current_head->VirtualAddress + current_head->Misc.VirtualSize + SELLCODESIZE);

	// 修改OEP
	nt_head_ptr->OptionalHeader.AddressOfEntryPoint = (current_head->VirtualAddress + current_head->Misc.VirtualSize);

	// 需要注意调整节的属性，让其能够访问
	current_head->Characteristics = current_head->Characteristics | 0x60000020;
	pePtr = imageBufferConvertFileBuffer(pePtr);
}

void addSectionCode(void *pePtr, int num)
{

	// 获取NT头，获取ImageBase，获取OEP
	PE_NT_Head *nt_head_ptr = getNTHead(pePtr);
	// 获取节表数量
	DWORD numberOfSections = nt_head_ptr->FileHeader.NumberOfSections;
	DWORD image_base = nt_head_ptr->OptionalHeader.ImageBase;
	DWORD addressOfEntryPoint = nt_head_ptr->OptionalHeader.AddressOfEntryPoint;

	// 检索这个节的空间是否足够
	IMAGE_SECTION_HEADER *section_heads = (IMAGE_SECTION_HEADER *)((DWORD)pePtr + ((PEDos *)pePtr)->e_lfanew + 4 + 20 + nt_head_ptr->FileHeader.SizeOfOptionalHeader);
	// 获取要注入代码的段
	IMAGE_SECTION_HEADER *current_head = section_heads;
	for (int i = 1; i <= numberOfSections; i++)
	{
		if (i == num)
		{
			break;
		}
		current_head++;
	}
	// 空间不足 表示注入不了
	if (current_head->Misc.VirtualSize < SELLCODESIZE)
	{
		return;
	}

	// 获取代码节点起始位置
	void *codeBegin = (void *)((DWORD)pePtr + current_head->VirtualAddress);

	// 将代码拷贝过去
	memccpy(codeBegin, shellCode, 1, SELLCODESIZE);

	// 修改E8
	DWORD *e8_code_ptr = (DWORD *)((DWORD)codeBegin + 0x9);
	*e8_code_ptr = (DWORD)(MESSAGEBOXAADDR - (image_base + current_head->VirtualAddress + 0xD));

	// 修改E9
	DWORD *e9_code_ptr = (DWORD *)((DWORD)codeBegin + 0xE);
	*e9_code_ptr = (image_base + addressOfEntryPoint) - (image_base + current_head->VirtualAddress + SELLCODESIZE);

	// 修改OEP
	nt_head_ptr->OptionalHeader.AddressOfEntryPoint = (current_head->VirtualAddress);

	// 需要注意调整节的属性，让其能够访问
	current_head->Characteristics = current_head->Characteristics | 0x60000020;
	pePtr = imageBufferConvertFileBuffer(pePtr);
}

// 移动头，把Dos头后面内容给移动上去
int moveNtHeadHandle(void *pePtr)
{
	PEDos *pe_dos_ptr = (PEDos *)pePtr;
	DWORD lfanew = pe_dos_ptr->e_lfanew;
	PE_NT_Head *nt_head = getNTHead(pePtr);

	DWORD numberOfSections = nt_head->FileHeader.NumberOfSections;
	DWORD sectionSize = 0x28;
	DWORD sizeOfOptionalHeader = nt_head->FileHeader.SizeOfOptionalHeader;
	DWORD fileHeadSize = sizeof(nt_head->FileHeader);

	DWORD ntToSectionSize = ((DWORD)nt_head + 4 + fileHeadSize + sizeOfOptionalHeader + (numberOfSections * sectionSize)) - (DWORD)nt_head;
	if (ntToSectionSize < 80)
	{
		printf("空间不足，无法移动NT头");
		return -1;
	}

	void *newNtHeadAddr = (void *)(pe_dos_ptr + 1);

	memcpy(newNtHeadAddr, (void *)nt_head, ntToSectionSize);
	pe_dos_ptr->e_lfanew = (DWORD)((DWORD)(pe_dos_ptr + 1) - (DWORD)pePtr);
	return 1;
}

// 新增节
void *addSection(void *pePtr)
{
	PEDos *peDosPtr = (PEDos *)pePtr;
	PE_NT_Head *nt_head = getNTHead(pePtr);
	DWORD sizeOfHeaders = nt_head->OptionalHeader.SizeOfHeaders;
	DWORD sizeOfImage = nt_head->OptionalHeader.SizeOfImage;
	DWORD numberOfSections = nt_head->FileHeader.NumberOfSections;

	DWORD sizeOfGarbageData = (DWORD)nt_head - (DWORD)pePtr;

	// 1.获取有几个节
	// 2.判断PE头是否能够存下我们新的内容
	// sizeOfHeaders - (Dos头 + Dos头到NT头的垃圾数据 + NT头标志 + 标准PE头 + 可选PE头 + x个节表)
	// 因为节表后面可能会紧挨着一段数据，所以要判断节表后面是不是有代码数据，如果有那么要考虑移动上面的空闲垃圾空间
	// 3.构建节表
	//
	// 4.把原本整个PE大小（sizeOfImage） + 新节表里的 文件大小
	// 5.填充代码

	DWORD free_space = sizeOfHeaders - (sizeOfGarbageData + 4 + sizeof(nt_head->FileHeader) + nt_head->FileHeader.SizeOfOptionalHeader + (numberOfSections * 0x28));
	if (free_space < 80)
	{
		// int reVal = moveNtHeadHandle(newPePtr);
		printf("空间不足，无法新增节表");
		return NULL;
	}

	char *free_space_ptr = (char *)((DWORD)peDosPtr + peDosPtr->e_lfanew + 4 + sizeof(nt_head->FileHeader) + nt_head->FileHeader.SizeOfOptionalHeader + (numberOfSections * 0x28));
	for (int i = 0; i < 80; i++)
	{
		if (*(free_space_ptr + i) != 0)
		{
			printf("剩余空间不足！此空间有代码！！！");
			return NULL;
		}
	}

	// 新开辟空间
	void *newPePtr = malloc(sizeOfImage + (0x1000));
	// 把新内容复制过去
	memcpy(newPePtr, pePtr, sizeOfImage);

	nt_head = getNTHead(newPePtr);
	// 检索这个节的空间是否足够
	IMAGE_SECTION_HEADER *section_heads = (IMAGE_SECTION_HEADER *)((DWORD)newPePtr + ((PEDos *)newPePtr)->e_lfanew + 4 + 20 + nt_head->FileHeader.SizeOfOptionalHeader);
	IMAGE_SECTION_HEADER *last_head_new = section_heads + (numberOfSections - 1);
	// 获取要注入代码的段
	IMAGE_SECTION_HEADER *current_head_new = section_heads + numberOfSections;

	// 构造新的节表结构
	char *name = ".tttt";
	char *name_ptr = (char *)current_head_new->Name;
	strncpy(name_ptr, name, 8);
	current_head_new->SizeOfRawData = 0x1000;
	current_head_new->Misc.VirtualSize = 0x1000;
	current_head_new->VirtualAddress = sizeOfImage;
	current_head_new->PointerToRawData = last_head_new->PointerToRawData + last_head_new->SizeOfRawData;
	current_head_new->Characteristics = 0x60000020;

	// 修改整体大小
	nt_head->OptionalHeader.SizeOfImage = sizeOfImage + (nt_head->OptionalHeader.FileAlignment * 2);
	// 修改节表数量
	nt_head->FileHeader.NumberOfSections = nt_head->FileHeader.NumberOfSections + 1;
	for (int i = 0; i < nt_head->FileHeader.NumberOfSections; i++)
	{
		IMAGE_SECTION_HEADER *tempSectionHeadPtr = section_heads + i;
		tempSectionHeadPtr->Characteristics = tempSectionHeadPtr->Characteristics | 0x60000020;
	}

	return newPePtr;
}

// 测试添加节
void testAddSection()
{
	// ---------------- FileBuffer ----------------
	// 把exe文件加载到内存
	void *pePtr = readExe("H:\\PETool 1.0.0.5.exe");
	moveNtHeadHandle(pePtr);
	PEDos *pe_dos_ptr = (PEDos *)pePtr;

	PE_NT_Head *nt_head = getNTHead(pePtr);
	DWORD sizeOfHeaders = nt_head->OptionalHeader.SizeOfHeaders;
	DWORD sizeOfImage = nt_head->OptionalHeader.SizeOfImage;
	DWORD numberOfSections = nt_head->FileHeader.NumberOfSections;

	DWORD sizeOfGarbageData = (DWORD)nt_head - (DWORD)pePtr;

	// 1.获取有几个节
	// 2.判断PE头是否能够存下我们新的内容
	// sizeOfHeaders - (Dos头 + Dos头到NT头的垃圾数据 + NT头标志 + 标准PE头 + 可选PE头 + x个节表)
	// 因为节表后面可能会紧挨着一段数据，所以要判断节表后面是不是有代码数据，如果有那么要考虑移动上面的空闲垃圾空间
	// 3.构建节表
	//
	// 4.把原本整个PE大小（sizeOfImage） + 新节表里的 文件大小
	// 5.填充代码

	DWORD free_space = sizeOfHeaders - (sizeOfGarbageData + 4 + sizeof(nt_head->FileHeader) + nt_head->FileHeader.SizeOfOptionalHeader + (numberOfSections * 0x28));
	// if (free_space < 80) {
	//	moveNtHeadHandle(pePtr);
	// }
	// moveNtHeadHandle(pePtr);

	char *free_space_ptr = (char *)((DWORD)pePtr + pe_dos_ptr->e_lfanew + 4 + sizeof(nt_head->FileHeader) + nt_head->FileHeader.SizeOfOptionalHeader + (numberOfSections * 0x28));
	// for (int i = 0; i < 80; i++)
	//{
	// if (*(free_space_ptr + i ) != 0) {
	//	printf("剩余空间不足！此空间有代码！！！");
	//		return;
	//	}
	//	}

	// 检索这个节的空间是否足够
	IMAGE_SECTION_HEADER *section_heads = (IMAGE_SECTION_HEADER *)((DWORD)pePtr + ((PEDos *)pePtr)->e_lfanew + 4 + 20 + nt_head->FileHeader.SizeOfOptionalHeader);
	IMAGE_SECTION_HEADER *last_head_new = section_heads + (numberOfSections - 1);
	// 获取要注入代码的段
	IMAGE_SECTION_HEADER *current_head_new = section_heads + numberOfSections;

	// 构造新的节表结构
	char *name = ".tttt";
	char *name_ptr = (char *)current_head_new->Name;
	strncpy(name_ptr, name, 8);
	current_head_new->SizeOfRawData = nt_head->OptionalHeader.FileAlignment * 2;
	current_head_new->Misc.VirtualSize = nt_head->OptionalHeader.SectionAlignment * 2;
	current_head_new->VirtualAddress = sizeOfImage;
	current_head_new->PointerToRawData = last_head_new->PointerToRawData + last_head_new->SizeOfRawData;
	current_head_new->Characteristics = 0x60000020;

	// 修改整体大小
	nt_head->OptionalHeader.SizeOfImage = sizeOfImage + (nt_head->OptionalHeader.FileAlignment * 2);
	// 修改节表数量
	nt_head->FileHeader.NumberOfSections = nt_head->FileHeader.NumberOfSections + 1;

	// 新开辟空间
	void *newPePtr = malloc(sizeOfImage + (nt_head->OptionalHeader.FileAlignment * 2));
	// 把新内容复制过去
	memcpy(newPePtr, pePtr, sizeOfImage);

	addSectionCode(newPePtr, nt_head->FileHeader.NumberOfSections);
}

// 扩大节
void *expandLastSection(void *pePtr)
{
	PEDos *peDosPtr = (PEDos *)pePtr;
	PE_NT_Head *ntHeadPtr = getNTHead(pePtr);
	DWORD numberOfSections = ntHeadPtr->FileHeader.NumberOfSections;
	DWORD sizeOfOptionalHeader = ntHeadPtr->FileHeader.SizeOfOptionalHeader;
	DWORD originSizeOfImage = ntHeadPtr->OptionalHeader.SizeOfImage;

	IMAGE_OPTIONAL_HEADER32 *optionPtr = (IMAGE_OPTIONAL_HEADER32 *)(ntHeadPtr->OptionalHeader);
	IMAGE_SECTION_HEADER *section_heads = (IMAGE_SECTION_HEADER *)((DWORD)optionPtr + sizeOfOptionalHeader);

	// 扩展大小
	DWORD expandValue = 0x1000;
	DWORD newSizeOfImage = originSizeOfImage + expandValue;
	// 构建新的空间
	void *newPePtr = malloc(newSizeOfImage);
	memcpy(newPePtr, pePtr, newSizeOfImage);
	PE_NT_Head *newNtHeadPtr = getNTHead(newPePtr);
	newNtHeadPtr->OptionalHeader.SizeOfImage = newSizeOfImage;
	IMAGE_OPTIONAL_HEADER32 *newOptionPtr = (IMAGE_OPTIONAL_HEADER32 *)(newNtHeadPtr->OptionalHeader);
	IMAGE_SECTION_HEADER *newSectionHeadsPtr = (IMAGE_SECTION_HEADER *)((DWORD)newOptionPtr + sizeOfOptionalHeader);

	// 获取最后一个节
	IMAGE_SECTION_HEADER *lastSection = newSectionHeadsPtr + (numberOfSections - 1);
	lastSection->SizeOfRawData += expandValue;
	lastSection->Misc.VirtualSize += expandValue;

	// 修改节属性，保证可执行，这里最保险的办法就是把每个节的属性全包括（这里的错误找了好久！！前面学习过程中都是满足可读可执行就可以了，即0x60000020，但这里不行！必须把所有节的属性都包含，0xC0000040才行）
	for (i = 0; i < numberOfSections - 1; i++)
	{
		newSectionHeadsPtr->Characteristics = newSectionHeadsPtr->Characteristics | (newSectionHeadsPtr + i)->Characteristics;
	}
	return newPePtr;
}

void printTable()
{
	// 把exe文件加载到内存
	void *pePtr = readExe("H:\\DTDebug.exe");
	PEDos *pe_dos_ptr = (PEDos *)pePtr;

	IMAGE_DATA_DIRECTORY *dataPtr = (IMAGE_DATA_DIRECTORY *)((DWORD)pePtr + pe_dos_ptr->e_lfanew + 4 + 20 + 96);
	for (int i = 1; i <= 16; i++)
	{
		printf("数据目录第%d \n", i);
		printf("内存地址：%x \n", dataPtr->VirtualAddress);
		printf("大小：%x \n", dataPtr->Size);
		dataPtr++;
	}
}

// 打印导出表
void testPrintImportTable(void *pePtr)
{
	// void *pePtr = readExe("H:\\DTDebug.exe");
	PEDos *pe_dos_ptr = (PEDos *)pePtr;

	// 获取第一个导出表
	IMAGE_DATA_DIRECTORY *dataPtr = (IMAGE_DATA_DIRECTORY *)((DWORD)pePtr + pe_dos_ptr->e_lfanew + 4 + 20 + 96);
	void *offerSet = RvaToFileOffset(pePtr, dataPtr->VirtualAddress);
	printf("数据目录name:%x,%x\n", offerSet, dataPtr->VirtualAddress);
	IMAGE_EXPORT_DIRECTORY *importBuild = (IMAGE_EXPORT_DIRECTORY *)((DWORD)pePtr + (DWORD)offerSet);

	printf("导出表基础信息打印\n");
	printf("导出表name:%x\n", importBuild->Name);
	printf("导出表base:%x\n", importBuild->Base);
	printf("导出表NumberOfFunctions:%x\n", importBuild->NumberOfFunctions);
	printf("导出表NumberOfNames:%x\n", importBuild->NumberOfNames);
	printf("导出表AddressOfFunctions:%x\n", importBuild->AddressOfFunctions);
	printf("导出表AddressOfNames:%x\n", importBuild->AddressOfNames);
	printf("导出表AddressOfNameOrdinals:%x\n", importBuild->AddressOfNameOrdinals);

	// 打印函数地址表
	DWORD *currentFunctionPtr = (DWORD *)((DWORD)pePtr + (DWORD)RvaToFileOffset(pePtr, importBuild->AddressOfFunctions));
	for (int i = 0; i < importBuild->NumberOfFunctions; i++)
	{
		printf("函数地址%x：%x\n", i, *(currentFunctionPtr));
		currentFunctionPtr++;
	}

	// 打印函数名
	DWORD *currentFunctionNamePtr = (DWORD *)((DWORD)pePtr + (DWORD)RvaToFileOffset(pePtr, importBuild->AddressOfNames));
	for (int i = 0; i < importBuild->NumberOfNames; i++)
	{
		char *functionNamePtr = (char *)((DWORD)pePtr + (DWORD)RvaToFileOffset(pePtr, *(currentFunctionNamePtr)));
		printf("函数名称%x：%s\n", i, functionNamePtr);
		currentFunctionNamePtr++;
	}

	// 打印函数序号表
	WORD *currentFunctionOrdinalPtr = (WORD *)((DWORD)pePtr + (DWORD)RvaToFileOffset(pePtr, importBuild->AddressOfNameOrdinals));
	for (int i = 0; i < importBuild->NumberOfNames; i++)
	{
		printf("函数序号%x：%d\n", i, *(currentFunctionOrdinalPtr) + importBuild->Base);
		currentFunctionOrdinalPtr++;
	}
}

// 根据函数名称找到函数地址
void *getFunctionAddrByName(void *pePtr, char *functionName)
{
	PEDos *pe_dos_ptr = (PEDos *)pePtr;
	// 获取第一个导出表
	IMAGE_DATA_DIRECTORY *dataPtr = (IMAGE_DATA_DIRECTORY *)((DWORD)pePtr + pe_dos_ptr->e_lfanew + 4 + 20 + 96);
	void *offerSet = RvaToFileOffset(pePtr, dataPtr->VirtualAddress);
	IMAGE_EXPORT_DIRECTORY *importBuild = (IMAGE_EXPORT_DIRECTORY *)((DWORD)pePtr + (DWORD)offerSet);

	printf("打印要找的函数函数名称：%s\n", functionName);
	printf("导出表基础信息打印\n");
	printf("导出表name:%x\n", importBuild->Name);
	printf("导出表base:%x\n", importBuild->Base);
	printf("导出表NumberOfFunctions:%x\n", importBuild->NumberOfFunctions);
	printf("导出表NumberOfNames:%x\n", importBuild->NumberOfNames);
	printf("导出表AddressOfFunctions:%x\n", importBuild->AddressOfFunctions);
	printf("导出表AddressOfNames:%x\n", importBuild->AddressOfNames);
	printf("导出表AddressOfNameOrdinals:%x\n", importBuild->AddressOfNameOrdinals);

	// 根据函数名找到下标
	int functionNameIndex = -1;
	DWORD *currentFunctionNamePtr = (DWORD *)((DWORD)pePtr + (DWORD)RvaToFileOffset(pePtr, importBuild->AddressOfNames));
	for (int i = 0; i < importBuild->NumberOfNames; i++)
	{
		char *functionNamePtr = (char *)((DWORD)pePtr + (DWORD)RvaToFileOffset(pePtr, *(currentFunctionNamePtr + i)));
		printf("函数名称%x：%s\n", i, functionNamePtr);
		// 判断函数名称是否一致
		if (strcmp(functionNamePtr, functionName) == 0)
		{
			functionNameIndex = i;
			break;
		}
	}

	if (functionNameIndex == -1)
	{
		printf("没有找到匹配的函数名称\n");
		return NULL;
	}

	// 根据函数名称的下标 找到对应的 函数序号表里的下标里面的值
	WORD *currentFunctionOrdinalPtr = (WORD *)((DWORD)pePtr + (DWORD)RvaToFileOffset(pePtr, importBuild->AddressOfNameOrdinals));
	WORD functionIndex = *(currentFunctionOrdinalPtr + functionNameIndex);
	printf("函数下标%x\n", functionIndex);

	// 根据函数序号表里的值 + 函数地址表起始地址 = 这个函数的真正地址
	DWORD *currentFunctionPtr = (DWORD *)((DWORD)pePtr + (DWORD)RvaToFileOffset(pePtr, importBuild->AddressOfFunctions));
	void *finalFunctionAddress = (void *)*(currentFunctionPtr + functionIndex);

	return finalFunctionAddress;
}

// 根据函数序号找到函数地址
void *getFunctionAddrByOrdinals(void *pePtr, DWORD functionOrdinal)
{
	PEDos *pe_dos_ptr = (PEDos *)pePtr;
	// 获取第一个导出表
	IMAGE_DATA_DIRECTORY *dataPtr = (IMAGE_DATA_DIRECTORY *)((DWORD)pePtr + pe_dos_ptr->e_lfanew + 4 + 20 + 96);
	void *offerSet = RvaToFileOffset(pePtr, dataPtr->VirtualAddress);
	IMAGE_EXPORT_DIRECTORY *importBuild = (IMAGE_EXPORT_DIRECTORY *)((DWORD)pePtr + (DWORD)offerSet);

	printf("打印要找的函数序号：%d\n", functionOrdinal);
	printf("导出表基础信息打印\n");
	printf("导出表name:%x\n", importBuild->Name);
	printf("导出表base:%x\n", importBuild->Base);
	printf("导出表NumberOfFunctions:%x\n", importBuild->NumberOfFunctions);
	printf("导出表NumberOfNames:%x\n", importBuild->NumberOfNames);
	printf("导出表AddressOfFunctions:%x\n", importBuild->AddressOfFunctions);
	printf("导出表AddressOfNames:%x\n", importBuild->AddressOfNames);
	printf("导出表AddressOfNameOrdinals:%x\n", importBuild->AddressOfNameOrdinals);

	// 导出序号 - Base的值就是函数地址下标
	DWORD finalFunctionIndex = functionOrdinal - importBuild->Base;

	if (finalFunctionIndex > importBuild->NumberOfFunctions + 1)
	{
		printf("没有找到匹配的函数下标地址\n");
		return NULL;
	}

	DWORD *currentFunctionPtr = (DWORD *)((DWORD)pePtr + (DWORD)RvaToFileOffset(pePtr, importBuild->AddressOfFunctions));
	void *finalFunctionAddress = (void *)*(currentFunctionPtr + finalFunctionIndex);
	return finalFunctionAddress;
}

void getFunctionNameByAddress(void *pePtr, void *functionAddress)
{
	PEDos *pe_dos_ptr = (PEDos *)pePtr;
	// 获取第一个导出表
	IMAGE_DATA_DIRECTORY *dataPtr = (IMAGE_DATA_DIRECTORY *)((DWORD)pePtr + pe_dos_ptr->e_lfanew + 4 + 20 + 96);
	void *offerSet = RvaToFileOffset(pePtr, dataPtr->VirtualAddress);
	IMAGE_EXPORT_DIRECTORY *importBuild = (IMAGE_EXPORT_DIRECTORY *)((DWORD)pePtr + (DWORD)offerSet);

	printf("导出表基础信息打印\n");
	printf("导出表name:%x\n", importBuild->Name);
	printf("导出表base:%x\n", importBuild->Base);
	printf("导出表NumberOfFunctions:%x\n", importBuild->NumberOfFunctions);
	printf("导出表NumberOfNames:%x\n", importBuild->NumberOfNames);
	printf("导出表AddressOfFunctions:%x\n", importBuild->AddressOfFunctions);
	printf("导出表AddressOfNames:%x\n", importBuild->AddressOfNames);
	printf("导出表AddressOfNameOrdinals:%x\n", importBuild->AddressOfNameOrdinals);

	// 打印函数地址表
	DWORD *currentFunctionPtr = (DWORD *)((DWORD)pePtr + (DWORD)RvaToFileOffset(pePtr, importBuild->AddressOfFunctions));
	WORD functionIndex = -1;
	for (int i = 0; i < importBuild->NumberOfFunctions; i++)
	{
		printf("函数地址%x：%x\n", i, *(currentFunctionPtr));
		if (*(currentFunctionPtr) == ((DWORD)functionAddress))
		{
			functionIndex = i;
			break;
		}
		currentFunctionPtr++;
	}

	// 打印函数序号表
	WORD *currentFunctionOrdinalPtr = (WORD *)((DWORD)pePtr + (DWORD)RvaToFileOffset(pePtr, importBuild->AddressOfNameOrdinals));
	int functionOrdinalIndex = -1;
	for (int i = 0; i < importBuild->NumberOfNames; i++)
	{
		printf("函数序号%x：%d\n", i, *(currentFunctionOrdinalPtr));
		if (*(currentFunctionOrdinalPtr) == functionIndex)
		{
			functionOrdinalIndex = i;
			break;
		}
		currentFunctionOrdinalPtr++;
	}

	// 打印函数名
	DWORD *currentFunctionNamePtr = (DWORD *)((DWORD)pePtr + (DWORD)RvaToFileOffset(pePtr, importBuild->AddressOfNames));
	char *functionNamePtr = (char *)((DWORD)pePtr + (DWORD)RvaToFileOffset(pePtr, *(currentFunctionNamePtr + functionOrdinalIndex)));
	printf("找到的函数名称：%s\n", functionNamePtr);
}

// 打印重定位表
void printfRelocationTable()
{
	void *pePtr = readExe("H:\\mydll.dll");
	PEDos *pe_dos_ptr = (PEDos *)pePtr;
	// 获取第一个导出表
	IMAGE_DATA_DIRECTORY *dataPtr = (IMAGE_DATA_DIRECTORY *)((DWORD)pePtr + pe_dos_ptr->e_lfanew + 4 + 20 + 96);
	// 获取到重定位表
	dataPtr += 5;
	void *offerSet = RvaToFileOffset(pePtr, dataPtr->VirtualAddress);
	IMAGE_BASE_RELOCATION *relocationTablePtr = (_IMAGE_BASE_RELOCATION *)((DWORD)pePtr + (DWORD)offerSet);

	if (relocationTablePtr->SizeOfBlock == 0)
	{
		printf("没有重定位表\n");
		return;
	}

	IMAGE_BASE_RELOCATION *currentRelocationPtr = relocationTablePtr;
	while (currentRelocationPtr->SizeOfBlock != 0 && currentRelocationPtr->VirtualAddress != 0)
	{
		if (currentRelocationPtr->SizeOfBlock > dataPtr->Size)
		{
			break;
		}
		printf("重定位表的基值：%x\n", currentRelocationPtr->VirtualAddress);
		printf("重定位表的大小：%x\n", currentRelocationPtr->SizeOfBlock);
		// 计算重定位表里的重定位项数量
		DWORD relocationCount = (currentRelocationPtr->SizeOfBlock - 8) / 2;
		printf("重定位表里的重定位项数量：%x\n", relocationCount);
		WORD *currentRelocationItemPtr = (WORD *)((DWORD)currentRelocationPtr + 8);
		for (int i = 0; i < relocationCount; i++)
		{

			// 判断高三位 如果 不是3就跳过
			if (((*currentRelocationItemPtr) & 0xF000) != 0x3000)
			{
				currentRelocationItemPtr += 1;
				continue;
			}
			// 修复重定位表
			// 这里注意 这里不是修复的重定位表项
			// 而是找到重定位表项里存储的真实地址
			// 找到以后，修改这个真实地址里保存的内容 + 偏移
			// 为什么要这么做？这个重定位表里的真实地址里存储真实的编码，也就是DLL里存储写死的函数地址，或者是硬编码后面写死的地址
			// 重定位表记录的是要被修改内容的地址
			WORD *finalItemValue = (WORD *)(*currentRelocationItemPtr & 0x0FFF);
			printf("重定位项%x：存储的偏移值：%x，基值叠加：%x, 最终值：%x\n", i, finalItemValue, currentRelocationPtr->VirtualAddress + (WORD)currentRelocationItemPtr, (DWORD)pePtr + currentRelocationPtr->VirtualAddress + (WORD)currentRelocationItemPtr);
			currentRelocationItemPtr += 1;
		}
		// 移动到下一个重定位表
		currentRelocationPtr = (IMAGE_BASE_RELOCATION *)((DWORD)currentRelocationPtr + currentRelocationPtr->SizeOfBlock);
	}
}

// 移动导出表
void moveExportTable()
{
	void *pePtr = readExe("H:\\mydll.dll");
	PEDos *pe_dos_ptr = (PEDos *)pePtr;

	// 获取第一个导出表
	IMAGE_DATA_DIRECTORY *dataPtr = (IMAGE_DATA_DIRECTORY *)((DWORD)pePtr + pe_dos_ptr->e_lfanew + 4 + 20 + 96);
	void *offerSet = RvaToFileOffset(pePtr, dataPtr->VirtualAddress);
	// 获取导出表
	IMAGE_EXPORT_DIRECTORY *importBuild = (IMAGE_EXPORT_DIRECTORY *)((DWORD)pePtr + (DWORD)offerSet);

	// 新增节
	void *newPePtr = addSection(pePtr);
	PE_NT_Head *nt_head_ptr = getNTHead(newPePtr);
	DWORD sizeOfImage = nt_head_ptr->OptionalHeader.SizeOfImage;
	DWORD numberOfSections = nt_head_ptr->FileHeader.NumberOfSections;
	IMAGE_SECTION_HEADER *section_heads = (IMAGE_SECTION_HEADER *)((DWORD)newPePtr + ((PEDos *)newPePtr)->e_lfanew + 4 + 20 + nt_head_ptr->FileHeader.SizeOfOptionalHeader);
	IMAGE_SECTION_HEADER *current_head = section_heads + numberOfSections - 1;
	// 获取第一个导出表
	IMAGE_DATA_DIRECTORY *newDataPtr = (IMAGE_DATA_DIRECTORY *)((DWORD)newPePtr + pe_dos_ptr->e_lfanew + 4 + 20 + 96);

	// 空间不足 表示注入不了
	if (current_head->Misc.VirtualSize < SELLCODESIZE)
	{
		return;
	}

	// 获取函数地址起始位置
	DWORD *oldFunctionAddressStart = (DWORD *)((DWORD)pePtr + (DWORD)RvaToFileOffset(pePtr, importBuild->AddressOfFunctions));
	// 计算出要存放新节里的起始地址
	DWORD *newFunctionAddressStart = (DWORD *)((DWORD)newPePtr + current_head->PointerToRawData);
	// 拷贝
	memcpy(newFunctionAddressStart, oldFunctionAddressStart, importBuild->NumberOfFunctions * 4);

	// 获取函数序号表起始地址
	WORD *oldFunctionOrdinalsStart = (WORD *)((DWORD)pePtr + (DWORD)RvaToFileOffset(pePtr, importBuild->AddressOfNameOrdinals));
	// 计算出要存放新节里的起始地址
	WORD *newFunctionOrdinalsStart = (WORD *)((DWORD)newFunctionAddressStart + (importBuild->NumberOfFunctions * 4));
	// 拷贝
	memcpy(newFunctionAddressStart, oldFunctionAddressStart, importBuild->NumberOfFunctions * 2);

	// 获取函数名称表起始地址
	DWORD *oldFunctionAddressOfNamesStart = (DWORD *)((DWORD)pePtr + (DWORD)RvaToFileOffset(pePtr, importBuild->AddressOfNames));
	// 计算出新的存储函数名字地址的起始位置
	DWORD *newFunctionAddressOfNamesStart = (DWORD *)((DWORD)newFunctionOrdinalsStart + (importBuild->NumberOfFunctions * 2));
	// 计算出新的 存储函数名字的起始位置
	DWORD *newFunctionNamesStart = (DWORD *)((DWORD)newFunctionAddressOfNamesStart + (importBuild->NumberOfFunctions * 4));
	for (int i = 0; i < importBuild->NumberOfNames; i++)
	{
		// 这里是把函数名称地址给变更位置
		char *functionNamePtr = (char *)((DWORD)pePtr + (DWORD)RvaToFileOffset(pePtr, *(oldFunctionAddressOfNamesStart + i)));
		// 这里是把函数名称这个字符串给变更位置
		// 拷贝字符串,这里需要注意要+1
		memcpy(newFunctionNamesStart, functionNamePtr, strlen(functionNamePtr) + 1);
		*(newFunctionAddressOfNamesStart + i) = (DWORD)FoaToRvaOffset(newPePtr, (DWORD)newFunctionNamesStart - (DWORD)newPePtr);

		// 这里记得移动新节存储函数名字的指针
		newFunctionNamesStart = (DWORD *)((DWORD)newFunctionNamesStart + strlen(functionNamePtr) + 1);
	}

	// 这里把整个导出表基础结构都拷贝到新节里
	DWORD *newExportBuild = newFunctionNamesStart;
	memcpy(newExportBuild, importBuild, 40);

	// 存放新的函数地址
	((IMAGE_EXPORT_DIRECTORY *)newExportBuild)->AddressOfFunctions = (DWORD)FoaToRvaOffset(newPePtr, (DWORD)newFunctionAddressStart - (DWORD)newPePtr);
	// 存放新的函数序号表的起始地址
	((IMAGE_EXPORT_DIRECTORY *)newExportBuild)->AddressOfNameOrdinals = (DWORD)FoaToRvaOffset(newPePtr, (DWORD)newFunctionOrdinalsStart - (DWORD)newPePtr);
	// 存放新的函数名字地址的起始地址
	((IMAGE_EXPORT_DIRECTORY *)newExportBuild)->AddressOfNames = (DWORD)FoaToRvaOffset(newPePtr, (DWORD)newFunctionAddressOfNamesStart - (DWORD)newPePtr);

	// 记得更改数据目录表里的地址
	newDataPtr->VirtualAddress = (DWORD)FoaToRvaOffset(newPePtr, (DWORD)newExportBuild - (DWORD)newPePtr);

	writeExe("H:\\mydll3.dll", newPePtr, sizeOfImage);
}

// 移动重定位表
void moveRelocationTable()
{
	void *pePtr = readExe("H:\\mydll.dll");
	PEDos *pe_dos_ptr = (PEDos *)pePtr;
	// 获取第一个重定位表
	IMAGE_DATA_DIRECTORY *dataPtr = (IMAGE_DATA_DIRECTORY *)((DWORD)pePtr + pe_dos_ptr->e_lfanew + 4 + 20 + 96);
	// 获取到重定位表
	dataPtr += 5;
	void *offerSet = RvaToFileOffset(pePtr, dataPtr->VirtualAddress);
	IMAGE_BASE_RELOCATION *relocationTablePtr = (_IMAGE_BASE_RELOCATION *)((DWORD)pePtr + (DWORD)offerSet);

	if (relocationTablePtr->SizeOfBlock == 0)
	{
		printf("没有重定位表\n");
		return;
	}

	// 新增节
	void *newPePtr = addSection(pePtr);
	PE_NT_Head *nt_head_ptr = getNTHead(newPePtr);
	DWORD sizeOfImage = nt_head_ptr->OptionalHeader.SizeOfImage;
	DWORD numberOfSections = nt_head_ptr->FileHeader.NumberOfSections;
	IMAGE_SECTION_HEADER *section_heads = (IMAGE_SECTION_HEADER *)((DWORD)pePtr + ((PEDos *)pePtr)->e_lfanew + 4 + 20 + nt_head_ptr->FileHeader.SizeOfOptionalHeader);
	IMAGE_SECTION_HEADER *current_head = section_heads + numberOfSections - 1;

	// 空间不足 表示注入不了
	if (current_head->Misc.VirtualSize < SELLCODESIZE)
	{
		return;
	}

	// 计算出要存放新节里的起始地址
	DWORD *newRelocationTableStart = (DWORD *)((DWORD)newPePtr + current_head->PointerToRawData);
	while (relocationTablePtr->SizeOfBlock != 0 && relocationTablePtr->VirtualAddress != 0)
	{
		// 拷贝内容
		memcpy(newRelocationTableStart, relocationTablePtr, relocationTablePtr->SizeOfBlock);
		// 移动到下一个重定位表
		relocationTablePtr = (IMAGE_BASE_RELOCATION *)((DWORD)relocationTablePtr + relocationTablePtr->SizeOfBlock);
		newRelocationTableStart = (DWORD *)((DWORD)newRelocationTableStart + relocationTablePtr->SizeOfBlock);
	}
	// 注意这里还需要拷贝最后为0的重定位表
	memcpy(newRelocationTableStart, relocationTablePtr, 8);
	dataPtr->VirtualAddress = (DWORD)FoaToRvaOffset(newPePtr, current_head->PointerToRawData);
	writeExe("H:\\mydll2.dll", newPePtr, sizeOfImage);
}

// 修复重定位表
void rebuildRelocationTable()
{
	void *pePtr = readExe("H:\\mydll.dll");
	PEDos *pe_dos_ptr = (PEDos *)pePtr;
	// 获取第一个重定位表
	IMAGE_DATA_DIRECTORY *dataPtr = (IMAGE_DATA_DIRECTORY *)((DWORD)pePtr + pe_dos_ptr->e_lfanew + 4 + 20 + 96);
	// 获取到重定位表
	dataPtr += 5;
	void *offerSet = RvaToFileOffset(pePtr, dataPtr->VirtualAddress);
	IMAGE_BASE_RELOCATION *relocationTablePtr = (_IMAGE_BASE_RELOCATION *)((DWORD)pePtr + (DWORD)offerSet);

	if (relocationTablePtr->SizeOfBlock == 0)
	{
		printf("没有重定位表\n");
		return;
	}

	// 获取原本的OEP
	PE_NT_Head *nt_head_ptr = getNTHead(pePtr);
	DWORD originImageBase = nt_head_ptr->OptionalHeader.ImageBase;
	DWORD sizeOfImage = nt_head_ptr->OptionalHeader.SizeOfImage;
	// 设置新的OEP
	nt_head_ptr->OptionalHeader.ImageBase = originImageBase + 0x10000;
	// 获取差异值
	DWORD diffValue = nt_head_ptr->OptionalHeader.ImageBase - originImageBase;

	// 修复重定位表
	while (relocationTablePtr->VirtualAddress != 0 && relocationTablePtr->SizeOfBlock != 0)
	{
		DWORD size = (relocationTablePtr->SizeOfBlock - 8) / 2;
		// 获取块的起始地址
		WORD *relocationValue = (WORD *)((DWORD)relocationTablePtr + 8);
		for (int i = 0; i < size; i++)
		{
			// 判断高三位 如果 不是3就跳过
			if ((*relocationValue & 0xF000) != 0x3000)
			{
				relocationValue += 1;
				continue;
			}
			// 修复重定位表
			// 这里注意 这里不是修复的重定位表项
			// 而是找到重定位表项里存储的真实地址
			// 找到以后，修改这个真实地址里保存的内容 + 偏移
			// 为什么要这么做？这个重定位表里的真实地址里存储真实的编码，也就是DLL里存储写死的函数地址，或者是硬编码后面写死的地址
			// 重定位表记录的是要被修改内容的地址
			DWORD *foaAddrPtr = (DWORD *)((DWORD)pePtr + (DWORD)RvaToFileOffset(pePtr, relocationTablePtr->VirtualAddress + (DWORD)(*relocationValue & 0x0FFF)));
			*foaAddrPtr = *foaAddrPtr + diffValue;
			relocationValue += 1;
		}
		relocationTablePtr = (IMAGE_BASE_RELOCATION *)((DWORD)relocationTablePtr + relocationTablePtr->SizeOfBlock);
	}
	writeExe("H:\\mydll2.dll", pePtr, sizeOfImage);
}

// 打印导入表
void printfImportTable()
{
	void *pePtr = readExe("H:\\mydll.dll");
	PEDos *pe_dos_ptr = (PEDos *)pePtr;
	// 获取第一个数据目录表
	IMAGE_DATA_DIRECTORY *dataPtr = (IMAGE_DATA_DIRECTORY *)((DWORD)pePtr + pe_dos_ptr->e_lfanew + 4 + 20 + 96);
	// 找到导入表
	dataPtr += 1;
	IMAGE_IMPORT_DESCRIPTOR *importPtr = (IMAGE_IMPORT_DESCRIPTOR *)((DWORD)pePtr + (DWORD)RvaToFileOffset(pePtr, dataPtr->VirtualAddress));

	while (importPtr->OriginalFirstThunk != 0 || importPtr->FirstThunk != 0)
	{
		char *name = (char *)((DWORD)pePtr + (DWORD)RvaToFileOffset(pePtr, importPtr->Name));
		printf("导出表名字:%s\n", name);

		// 打印INT表
		printf("----打印INT表----\n");
		IMAGE_THUNK_DATA32 *intTablePtr = (IMAGE_THUNK_DATA32 *)((DWORD)pePtr + (DWORD)RvaToFileOffset(pePtr, importPtr->OriginalFirstThunk));
		while (*((DWORD *)intTablePtr) != 0)
		{
			if ((intTablePtr->Ordinal & 0x80000000) == 0x80000000)
			{
				// 一个IMAGE_THUNK_DATA32结构占用四字节，索引一个函数名/序号，但是索引是有条件的，即四字节的最高位如果为0则这四字节的值为IMAGE_IMPORT_BY_NAME的RVA；
				// 但是如果四字节的最高位为1，则不需要（不能够）用该值去索引IMAGE_IMPORT_BY_NAME，而是直接去掉最高位，剩下31位的值便是dll函数在导出表中的导出序号
				printf("INT表 存的是序号:%x\n", intTablePtr->Ordinal & 0x7fffffff);
			}
			else
			{
				// 走到这里代表是存的函数名称的RVA
				IMAGE_IMPORT_BY_NAME *functionNamePtr = (_IMAGE_IMPORT_BY_NAME *)((DWORD)pePtr + (DWORD)RvaToFileOffset(pePtr, intTablePtr->Function));
				printf("INT表 存的是函数名:%s\n", functionNamePtr->Name);
			}
			intTablePtr++;
		}

		printf("----打印IAT表----\n");
		// 打印IAT表
		IMAGE_THUNK_DATA32 *iatTablePtr = (IMAGE_THUNK_DATA32 *)((DWORD)pePtr + (DWORD)RvaToFileOffset(pePtr, importPtr->FirstThunk));
		while (*((DWORD *)iatTablePtr) != 0)
		{
			if ((iatTablePtr->Ordinal & 0x80000000) == 0x80000000)
			{
				// 一个IMAGE_THUNK_DATA32结构占用四字节，索引一个函数名/序号，但是索引是有条件的，即四字节的最高位如果为0则这四字节的值为IMAGE_IMPORT_BY_NAME的RVA；
				// 但是如果四字节的最高位为1，则不需要（不能够）用该值去索引IMAGE_IMPORT_BY_NAME，而是直接去掉最高位，剩下31位的值便是dll函数在导出表中的导出序号
				printf("IAT表 存的是序号:%x\n", iatTablePtr->Ordinal & 0x7fffffff);
			}
			else
			{
				// 走到这里代表是存的函数名称的RVA
				IMAGE_IMPORT_BY_NAME *functionNamePtr = (_IMAGE_IMPORT_BY_NAME *)((DWORD)pePtr + (DWORD)RvaToFileOffset(pePtr, iatTablePtr->Function));
				printf("IAT表 存的是函数名:%s\n", functionNamePtr->Name);
			}
			iatTablePtr++;
		}
		importPtr++;
	}
}

// 注入DLL,这里包含导入表移动
void injectDll(void *pePtr, char *dllName, char *functionNameArr[], int functionNameSize)
{
	void *pePtr = readExe("H:\\mydll.dll");
	PEDos *pe_dos_ptr = (PEDos *)pePtr;
	PE_NT_Head *ntHeadPtr = getNTHead(pePtr);
	DWORD numberOfSections = ntHeadPtr->FileHeader.NumberOfSections;

	// 获取导入表数据目录
	IMAGE_DATA_DIRECTORY *dataDirectoryPtr = ntHeadPtr->OptionalHeader.DataDirectory[1];

	// 获取导入表
	IMAGE_IMPORT_DESCRIPTOR *importPtr = (IMAGE_IMPORT_DESCRIPTOR *)((DWORD)pePtr + (DWORD)RvaToFileOffset(pePtr, dataDirectoryPtr->VirtualAddress));

	// 新增节，或者扩大节
	void *newPePtr = addSection(pePtr);
	if (newPePtr == NULL)
	{
		// 如果没办法新增节，那么可以扩大节
		newPePtr = expandLastSection(pePtr);
	}

	PE_NT_Head *newNtHeadPtr = getNTHead(newPePtr);
	// 获取节表起始地址
	IMAGE_SECTION_HEADER *sectionHeads = (IMAGE_SECTION_HEADER *)((DWORD)newPePtr + ((PEDos *)newPePtr)->e_lfanew + 4 + 20 + nt_head_ptr->FileHeader.SizeOfOptionalHeader);
	// 获取最后一个节表
	IMAGE_SECTION_HEADER *lastSectionHeadPtr = sectionHeads + (numberOfSections - 1);
	// 获取导入表
	IMAGE_DATA_DIRECTORY *newDataDirectoryPtr = newNtHeadPtr->OptionalHeader.DataDirectory[1];
	// 计算出当前pe多大
	DWORD bufferSize = lastSectionHeadPtr->PointerToRawData + lastSectionHeadPtr->SizeOfRawData;
	// 计算出来新的导入表存入的地址
	void *newImportAddrPtr = (void *)(bufferSize - 0x1000);
	void *newCurrentImportPtr = newImportAddrPtr;
	// 创建一个游标指针
	IMAGE_IMPORT_DESCRIPTOR *currentImportPtr = importPtr;
	IMAGE_THUNK_DATA32 *intTablePtr = NULL;
	IMAGE_THUNK_DATA32 *iatTablePtr = NULL;

	while (true)
	{
		if (currentImportPtr->ForwarderChain == 0 || currentImportPtr->OriginalFirstThunk == 0)
		{
			break;
		}
		// 把导入表数据Copy过去
		memcpy(newCurrentImportPtr, currentImportPtr, sizeof(IMAGE_IMPORT_DESCRIPTOR));
		newCurrentImportPtr = (DWORD)newImportAddrPtr + sizeof(IMAGE_IMPORT_DESCRIPTOR);
		// 移动导入表指针 指向下一个导入表
		currentImportPtr++;
	}
	// 新的导入表
	IMAGE_IMPORT_DESCRIPTOR *newImportDescriptorPtr = (IMAGE_IMPORT_DESCRIPTOR *)newCurrentImportPtr;
	// 多留一块空间为了放0，也就是结束导入表
	newCurrentImportPtr = (void *)((DWORD)newCurrentImportPtr + (sizeof(IMAGE_IMPORT_DESCRIPTOR) * 2));

	// 准备INT表，并指向起始地址
	intTablePtr = (IMAGE_THUNK_DATA32 *)newCurrentImportPtr;
	// 跳过INT表
	newCurrentImportPtr = (void *)((DWORD)newCurrentImportPtr + (sizeof(IMAGE_THUNK_DATA32) * functionNameSize));

	// 准备IAT表，并指向起始地址
	iatTablePtr = (IMAGE_THUNK_DATA32 *)newCurrentImportPtr;
	newCurrentImportPtr = (void *)((DWORD)newCurrentImportPtr + (sizeof(IMAGE_THUNK_DATA32) * functionNameSize));

	// 把新的INT表地址复制到导入表中
	newImportDescriptorPtr->FirstThunk = FoaToRvaOffset(newPePtr, (DWORD)intTablePtr - (DWORD)newPePtr);
	// 把新的IAT表地址复制到导入表中
	newImportDescriptorPtr->OriginalFirstThunk = FoaToRvaOffset(newPePtr, (DWORD)iatTablePtr - (DWORD)newPePtr);

	// 准备函数名称信息表，并指向起始地址
	IMAGE_IMPORT_BY_NAME *importNamePtr = (IMAGE_IMPORT_BY_NAME *)newCurrentImportPtr;
	for (int i = 0; i < functionNameSize; i++)
	{
		char *functionName = functionNameArr[i];
		importNamePtr->Hint = i;
		strncpy(importNamePtr->Name, functionName, strlen(functionName) + 1);

		// 把这个函数名称信息表移动到INT表中
		intTablePtr->Function = FoaToRvaOffset(newPePtr, (DWORD)importNamePtr - (DWORD)newPePtr);
		// 把这个函数名称信息表移动到IAT表中
		iatTablePtr->Function = FoaToRvaOffset(newPePtr, (DWORD)importNamePtr - (DWORD)newPePtr);

		// 这里要移动这个指针，移动的距离是 当前指针位置 + IMAGE_IMPORT_BY_NAME->Hint + 字符串长度 + sizeof(\0)
		newCurrentImportPtr = (void *)((DWORD)newCurrentImportPtr + 2 + strlen(functionName) + 1);
		importNamePtr = (void *)((DWORD)importNamePtr + 2 + strlen(functionName) + 1);
		intTablePtr++;
		iatTablePtr++;
	}

	// 设置DLL名字
	strncpy(newCurrentImportPtr, dllName, strlen(dllName) + 1);
	newImportDescriptorPtr->Name = FoaToRvaOffset(newPePtr, (DWORD)newCurrentImportPtr - (DWORD)newPePtr);
	newCurrentImportPtr = (DWORD)newCurrentImportPtr + strlen(dllName) + 1;

	newDataDirectoryPtr->VirtualAddress = FoaToRvaOffset(newPePtr, (DWORD)newImportDescriptorPtr - (DWORD)newPePtr);
	newDataDirectoryPtr->Size = dataDirectoryPtr->Size + 20;

	writeExe("H:\\new\\PETool 1.0.0.55.exe", newPePtr, bufferSize);
}

void main()
{

	printfImportTable();

	// 移动导出表
	// moveExportTable();
	// void *pePtr = readExe("H:\\mydll.dll");
	// testPrintImportTable(pePtr);

	// printf("----------------------\n");
	// void *pePtr2 = readExe("H:\\mydll3.dll");
	// testPrintImportTable(pePtr2);

	// 打印重定位表
	// printfRelocationTable();

	// 测试根据函数名找到函数地址，根据函数地址找到函数名
	char *str = "_Runtracesize";
	// void* pePtr = readExe("H:\\DTDebug.exe");
	// void* addr = getFunctionAddrByName(pePtr, str);
	// void* addr2 = getFunctionAddrByOrdinals(pePtr, 0x7c);
	// getFunctionNameByAddress(pePtr, addr);
	// printf("地址是:%x", addr);
	// printf("地址2是:%x", addr2);

	// 测试打印导出表
	// testPrintImportTable();
	// writeTest("H:\\new2\\text.txt");

	// 测试添加节表
	// testAddSection();
	// void* pePtr = readExe("C:\\Windows\\System32\\notepad.exe");
	// void* new_memory = readImageBuffer(pePtr);
	// DWORD size_of_image = getSizeOfImage(pePtr);
	// writeExe("H:\\new\\notepad3.exe", new_memory, size_of_image);
	// free(pePtr);
	// free(new_memory);
}